home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / umddvi / lib / gffont.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  22KB  |  921 lines

  1. /*
  2.  * Copyright (c) 1987 University of Maryland Department of Computer Science.
  3.  * All rights reserved.  Permission to copy for any purpose is hereby granted
  4.  * so long as this copyright notice remains intact.
  5.  */
  6.  
  7. #ifndef lint
  8. static char rcsid[] = "$Header: gffont.c,v 2.5 87/06/16 18:28:13 chris Exp $";
  9. #endif
  10.  
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include "types.h"
  15. #include "font.h"
  16. #include "gfcodes.h"
  17. #include "gfclass.h"
  18. #include "num.h"
  19.  
  20. /*
  21.  * GF font operations.
  22.  *
  23.  * GF files may be compact, but this code surely is not!
  24.  *
  25.  * TODO:
  26.  *    think about fonts with characters outside [0..255]
  27.  *    find some way to free gf body when done
  28.  */
  29. int    gf_read(), gf_getgly(), gf_rasterise(), gf_freefont();
  30.  
  31. struct    fontops gfops =
  32.     { "gf", 1.0, gf_read, gf_getgly, gf_rasterise, gf_freefont };
  33.  
  34. /*
  35.  * Local info.
  36.  */
  37.  
  38. /*
  39.  * A bounding box.  The names follow those in the GF documentation.
  40.  */
  41. struct bounds {
  42.     i32    min_m, max_m;    /* min and max `m' (colunm) values */
  43.     i32    min_n, max_n;    /* min and max `n' (row) values */
  44. };
  45.  
  46. /*
  47.  * char_loc is one `character locator' from a GF file, save for the
  48.  * `character residue', which we need not.
  49.  */
  50. struct char_loc {
  51.     i32    cl_dx;        /* x escapement (scaled pixels) */
  52.     i32    cl_dy;        /* y escapement (scaled pixels) */
  53.     i32    cl_w;        /* TFM width */
  54.     i32    cl_p;        /* pointer to BOC (or specials) */
  55. };
  56.  
  57. /*
  58.  * GF details include:
  59.  *  ->    the main body of the GF file (all bytes save pre- and post-amble);
  60.  *  ->    global box boundaries;
  61.  * and    character locators, addressed by `character residue'.  Empty
  62.  *    slots are indicated by a -1 `pointer'.
  63.  */
  64. struct gf_details {
  65.     char    *gd_body;        /* GF body */
  66.     char    *gd_base;        /* == gd_body - preamble_size */
  67.     struct    bounds gd_gb;        /* global boundaries */
  68.     struct    char_loc gd_cl[256];    /* character locators */
  69. };
  70.  
  71. /*
  72.  * Get the gf_details from font f.
  73.  */
  74. #define    ftogd(f) ((struct gf_details *) (f)->f_details)
  75.  
  76. extern    int errno;
  77. char    *malloc(), *copyit();
  78.  
  79. /*
  80.  * I am making the assumption that 530 bytes will always be enough
  81.  * to find the end of the GF file.  12 should suffice, as there
  82.  * should be at most seven GF_FILLER bytes, preceded by the GF ID,
  83.  * preceded by the four byte postamble pointer; but at least one
  84.  * VMS TeX pads pads DVI files to a full `sector', so I am assuming
  85.  * it may do the same to GF files.
  86.  */
  87. #ifdef vms
  88. #define    POSTSIZE    530    /* make only VMS pay for its ways; */
  89. #else
  90. #define    POSTSIZE    16    /* others get to use something reasonable */
  91. #endif
  92.  
  93. /*
  94.  * Find the GF postamble.  Store the offsets of the POST and POSTPOST
  95.  * opcodes through postp and postpostp.
  96.  */
  97. static
  98. findGFpostamble(fd, postp, postpostp)
  99.     int fd;
  100.     long *postp, *postpostp;
  101. {
  102.     register long offset;
  103.     register char *p;
  104.     register int i;
  105.     register i32 n;
  106.     char postbuf[POSTSIZE];
  107.  
  108.     /*
  109.      * Avoid lseek()ing beyond beginning of file; it may give odd
  110.      * results.  Read the last POSTSIZE bytes (or however many we
  111.      * can get).
  112.      */
  113.     offset = lseek(fd, 0L, 2) - (long) POSTSIZE;
  114.     if (offset < 0L)
  115.         offset = 0L;
  116.     (void) lseek(fd, offset, 0);
  117.     i = read(fd, postbuf, POSTSIZE);
  118.     if (i <= 0)
  119.         return (-1);
  120.     p = &postbuf[i];
  121.     i -= 4;            /* account for the pointer in advance */
  122.  
  123.     /*
  124.      * Now search backwards for the GF_ID byte.  The postamble
  125.      * pointer will be four bytes behind that.
  126.      */
  127.     while (--i >= 0) {
  128.         if (UnSign8(*--p) == GF_ID)
  129.             goto foundit;
  130.         if (UnSign8(*p) != GF_FILLER)
  131.             break;
  132.     }
  133.     return (-1);        /* cannot find postamble ptr */
  134.  
  135. foundit:
  136.     /*
  137.      * Store the (presumed) position of the POSTPOST byte, which
  138.      * is i-1 bytes beyond `offset'.
  139.      */
  140.     *postpostp = offset + i - 1;
  141.  
  142.     /*
  143.      * Read out the postamble pointer and seek to the postamble,
  144.      * also saving the offset.
  145.      */
  146.     p -= 4;
  147.     pGetLong(p, n);
  148.     *postp = offset = n;
  149.     (void) lseek(fd, offset, 0);
  150.     return (0);        /* made it */
  151. }
  152.  
  153. /*
  154.  * Read a GF file.
  155.  */
  156. static int
  157. gf_read(f)
  158.     register struct font *f;
  159. {
  160.     register struct gf_details *gd;
  161.     register char *p;
  162.     register struct char_loc *cl;
  163.     register int i;
  164.     int fd, presize, postsize, bodysize, firstc, lastc;
  165.     char *postamble;
  166.     long postaddr, postpostaddr;
  167.     i32 lasteoc;
  168.     char *problem = NULL;
  169.     struct stat st;
  170.     char b[4];
  171.     int saverr;
  172.  
  173.     if ((fd = open(f->f_path, 0)) < 0)
  174.         return (-1);
  175.     gd = NULL;        /* prepare for failure */
  176.     postamble = NULL;
  177.  
  178.     /*
  179.      * The file had best be at least 50 bytes long.  A
  180.      * `completely empty' GF file might consist of a PRE, a GF_ID,
  181.      * no comment (one zero byte), then: POST, pointer to last
  182.      * EOC, design size, checksum, hppp, vppp, min_m, max_m,
  183.      * min_n, max_n, POSTPOST, pointer to POST, GF_ID, and four
  184.      * FILLERs.
  185.      */
  186.     (void) fstat(fd, &st);
  187.     if (st.st_size < 50) {    /* too small to be a GF file */
  188.         problem = "file is too short";
  189.         goto fail;
  190.     }
  191.  
  192.     /*
  193.      * Read the very beginning and pick up the preamble size.
  194.      */
  195.     if (read(fd, b, 4) != 4)
  196.         goto fail;
  197.     if (UnSign8(b[0]) != GF_PRE) {
  198.         problem = "file does not begin with PRE";
  199.         goto fail;
  200.     }
  201.     i = UnSign8(b[1]);
  202.     if (i != GF_ID)
  203.         error(0, 0, "Warning: strange GF id (%d) in \"%s\"", i,
  204.             f->f_path);
  205.     presize = 3 + UnSign8(b[2]);
  206.  
  207.     /*
  208.      * Find the postamble, allocate space, and read it in.
  209.      */
  210.     if (findGFpostamble(fd, &postaddr, &postpostaddr)) {
  211.         problem = "cannot find postamble";
  212.         goto fail;
  213.     }
  214.     postsize = postpostaddr - postaddr + 1;
  215.     if ((p = malloc(postsize)) == NULL)
  216.         goto fail;
  217.     if (read(fd, p, postsize) != postsize)
  218.         goto fail;
  219.     postamble = p;
  220.     
  221.     /*
  222.      * Make sure we found it.
  223.      */
  224.     if (pgetbyte(p) != GF_POST) {
  225.         problem = "no GF_POST at postamble";
  226.         goto fail;
  227.     }
  228.  
  229.     /*
  230.      * Looks okay.  Allocate detail space and poke through the postamble.
  231.      */
  232.     if ((gd = (struct gf_details *) malloc(sizeof (*gd))) == NULL)
  233.         goto fail;
  234.     gd->gd_body = NULL;
  235.  
  236.     pGetLong(p, lasteoc);    /* actually one past last EOC */
  237.     p += 4;            /* skip design size */
  238.     pGetLong(p, f->f_checksum);
  239.     p += 2 * 4;        /* hppp, vppp */
  240.  
  241.     pGetLong(p, gd->gd_gb.min_m);
  242.     pGetLong(p, gd->gd_gb.max_m);
  243.     pGetLong(p, gd->gd_gb.min_n);
  244.     pGetLong(p, gd->gd_gb.max_n);
  245.  
  246.     /*
  247.      * Zap all the character locators, then read those that are
  248.      * defined in the postamble.  Remember the first and last
  249.      * characters so that we know which glyphs are defined.  Lastc
  250.      * is actually the last-plus-one'th character.
  251.      */
  252.     for (cl = gd->gd_cl, i = 256; --i >= 0; cl++)
  253.         cl->cl_p = -1;
  254.     firstc = 256;
  255.     lastc = 0;
  256.     for (;;) {
  257.         i32 dx, dy;
  258.  
  259.         switch (pgetbyte(p)) {
  260.  
  261.         case GF_CHAR_LOC:
  262.             i = pgetbyte(p);
  263.             pGetLong(p, dx);
  264.             pGetLong(p, dy);
  265.             goto merge;
  266.  
  267.         case GF_CHAR_LOC0:
  268.             i = pgetbyte(p);
  269.             dx = ((i32) pgetbyte(p)) << 16;
  270.             dy = 0;
  271. merge:
  272.             if (i < firstc)
  273.                 firstc = i;
  274.             if (i >= lastc)
  275.                 lastc = i + 1;
  276.             cl = &gd->gd_cl[i];
  277.             cl->cl_dx = dx;
  278.             cl->cl_dy = dy;
  279.             pGetLong(p, cl->cl_w);
  280.             pGetLong(p, cl->cl_p);
  281.             break;
  282.  
  283.         case GF_POSTPOST:
  284.             goto done;
  285.  
  286.         default:
  287.             error(0, 0, "I do not understand %d here",
  288.                 UnSign8(p[-1]));
  289.             problem = "unexpected opcode in postamble";
  290.             goto fail;
  291.         }
  292.     }
  293. done:
  294.     free(postamble);
  295.     postamble = NULL;    /* all done with it */
  296.  
  297.     /*
  298.      * Alas, we need the instructions whether or not we need
  299.      * the rasters, since the raster bounding box information
  300.      * can only be properly determined by converting the rasters.
  301.      * Compute the size of the main body of the GF file, then
  302.      * read it in.
  303.      */
  304.     bodysize = lasteoc - presize;
  305.     if ((gd->gd_body = malloc(bodysize + 1)) == NULL)
  306.         goto fail;
  307.     (void) lseek(fd, (long) presize, 0);
  308.     if (read(fd, gd->gd_body, bodysize) != bodysize)
  309.         goto fail;
  310.     /*
  311.      * The next byte might be a special, so we just
  312.      * arbitrarily stuff in a POST.
  313.      */
  314.     gd->gd_body[bodysize] = GF_POST;
  315.     gd->gd_base = gd->gd_body - presize;
  316.  
  317.     f->f_details = (char *) gd;
  318.     if (FontHasGlyphs(f, firstc, lastc))
  319.         goto fail2;
  320.     (void) close(fd);
  321.     return (0);
  322.  
  323. fail:
  324.     if (problem == NULL)
  325.         error(0, errno, "trouble reading \"%s\"", f->f_path);
  326.     else
  327.         error(0, 0, "%s\n\t(are you sure \"%s\" is a GF file?)",
  328.             problem, f->f_path);
  329.     errno = 0;
  330. fail2:
  331.     saverr = errno;
  332.     if (postamble != NULL)
  333.         free(postamble);
  334.     if (gd != NULL) {
  335.         if (gd->gd_body != NULL)
  336.             free(gd->gd_body);
  337.         free((char *) gd);
  338.     }
  339.     (void) close(fd);
  340.     errno = saverr;
  341.     return (-1);
  342. }
  343.  
  344. /*
  345.  * Some global variables, used while building rasters.  (These are
  346.  * referenced also in copyit(), so must be global.  Fortunately, no
  347.  * one yet requires the font routines to be re-entrant.)
  348.  */
  349. static char *buildraster;    /* raster being built */
  350. static int buildsize;        /* size of buildraster (bytes) */
  351.  
  352. static struct bounds tempb;    /* bounds used during buildraster */
  353. static struct bounds ob;    /* observed bounds */
  354.  
  355. /*
  356.  * Bit tables: `left' and `right' bits.  lbits[b] has all the bits
  357.  * that are to the left of bit b set; rbits[b] has all the bits
  358.  * that are to the right of bit b set, as well as bit b itself.
  359.  */
  360. static char lbits[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
  361. static char rbits[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
  362.  
  363. /*
  364.  * The magic address `nullraster' is known in getgly() as a valid
  365.  * but empty raster, and changed there to NULL.  A NULL return from
  366.  * drawchar indicates failure; we need something to distinguish the
  367.  * empty raster.
  368.  */
  369. static char nullraster[1];
  370.  
  371. /*
  372.  * `Inline functions':
  373.  *  ->    convert a bit number to a byte number (round down);
  374.  *  ->    convert a number of bits to a number of bytes (round up);
  375.  * and    convert a bit to a bit index.
  376.  */
  377. #define btoby(b) ((b) >> 3)
  378. #define    btonb(b) (((b) + 7) >> 3)
  379. #define    btobi(b) ((b) & 7)
  380.  
  381. /*
  382.  * Helper function for getgly: build the raster, and compute its
  383.  * minimal bounding box.  Called with `p' pointing past the backpointer
  384.  * field of the BOC command (i.e., at min_m or del_m).  `abbrev' is true
  385.  * iff this was a BOC1.  `globalb' are the global bounds from the GF file,
  386.  * whose name is pointed to by gfname.
  387.  */
  388. static char *
  389. drawchar(p, abbrev, globalb, gfname)
  390.     register char *p;
  391.     int abbrev;
  392.     struct bounds globalb;
  393.     char *gfname;
  394. {
  395.     register i32 m;        /* m register (column) */
  396.     register char *colp;    /* pointer to byte corresponding to m */
  397.     register int c;        /* temporary */
  398.     register i32 i;        /* temporary */
  399.     register int black;    /* true when paint_switch==black */
  400.     register i32 n;        /* n register (row) */
  401.     int stride;        /* multiplier to convert linear to 2d array */
  402.     int wrotethisrow;    /* true iff we wrote in the current row */
  403.     char *virtrast;        /* virtual origin version of buildraster */
  404.     int mustcopy;        /* true if we must copy the built raster */
  405.     struct bounds gb;    /* bounds from the GF file */
  406.  
  407.     /* get the bounds */
  408.     if (abbrev) {
  409.         c = pgetbyte(p);/* del_m */
  410.         gb.min_m = (gb.max_m = pgetbyte(p)) - c;
  411.         c = pgetbyte(p);/* del_n */
  412.         gb.min_n = (gb.max_n = pgetbyte(p)) - c;
  413.     } else {
  414.         pGetLong(p, gb.min_m);
  415.         pGetLong(p, gb.max_m);
  416.         pGetLong(p, gb.min_n);
  417.         pGetLong(p, gb.max_n);
  418.     }
  419.  
  420.     /*
  421.      * Trim the GF bounds according to the global bounds.  We
  422.      * use the trimmed values to allocate the build space.
  423.      */
  424.     tempb = gb;
  425. #define    GB_ADJ(field, cmp) \
  426.     if (tempb.field cmp globalb.field) \
  427.         tempb.field = globalb.field
  428.     GB_ADJ(min_m, <);
  429.     GB_ADJ(max_m, >);
  430.     GB_ADJ(min_n, <);
  431.     GB_ADJ(max_n, >);
  432. #undef GB_ADJ
  433.  
  434.     /*
  435.      * Compute the distance between rows (the number of bytes per
  436.      * column), then make sure there is room in the build space
  437.      * for [min_n..max_n] of these, possibly by allocating a new raster.
  438.      */
  439.     stride = btonb(tempb.max_m - tempb.min_m + 1);
  440.     c = stride * (tempb.max_n - tempb.min_n + 1);
  441.     if (c <= 0)        /* completely empty character */
  442.         return (nullraster);
  443.     if (c > buildsize) {
  444.         if (buildraster != NULL)
  445.             free(buildraster);
  446.         if ((buildraster = malloc(c)) == NULL) {
  447.             buildsize = 0;
  448.             return (NULL);
  449.         }
  450.         buildsize = c;
  451.     }
  452.  
  453.     /*
  454.      * If we are using an old raster that is too big, remember to
  455.      * scrunch it down later.
  456.      */
  457.     mustcopy = buildsize > c;
  458.  
  459.     /* clear the raster to white */
  460.     bzero(buildraster, c);
  461.  
  462.     /*
  463.      * Make a virtual origin raster pointer.  The virtual origin is
  464.      * where raster[0][0] is, whether or not there is a raster[0][0].
  465.      * Normally, this would be
  466.      *    &buildraster[-gb.min_n * stride - btoby(gb.min_m)],
  467.      * but it is complicated by two things.  Firstly, we would like
  468.      * n==max_n to be the bottommost point in the raster (low
  469.      * addresses), and n==min_n to be the topmost (high addresses).
  470.      * In other words, we need to reflect the n (Y) values about
  471.      * the X axis: negate them.  Secondly, the raster we create
  472.      * must be `flush left'.  That is, somewhere along its rows,
  473.      * bit 0x80 must be set at the left edge of one of its columns.
  474.      * We need to subtract away the minimum bit index before
  475.      * calculating bit values.  This cannot really be done in
  476.      * advance, since we cannot address bits directly.
  477.      */
  478.     virtrast = &buildraster[gb.max_n * stride];
  479.  
  480.     /*
  481.      * Set up the bounds-trimming variables.  The observed m bounds
  482.      * are kept offset by gb.min_m until we finish drawing the
  483.      * character.
  484.      */
  485.     ob.min_m = tempb.max_m - gb.min_m + 1;
  486.     ob.max_m = tempb.min_m - gb.min_m - 1;
  487.     ob.min_n = tempb.max_n + 1;
  488.     ob.max_n = tempb.min_n - 1;
  489.     wrotethisrow = 0;
  490.  
  491. #define FIX_N_BOUNDS() { \
  492.     if (wrotethisrow) { \
  493.         c = -n; /* recall that n is reflected about X axis */ \
  494.         if (c < ob.min_n) \
  495.             ob.min_n = c; \
  496.         if (c > ob.max_n) \
  497.             ob.max_n = c; \
  498.         wrotethisrow = 0; \
  499.     } \
  500. }
  501.  
  502.     /*
  503.      * Initialise state variables: m = min_m, n = max_n,
  504.      * paint_switch = white.
  505.      */
  506.     m = 0;            /* gb.min_m - gb.min_m */
  507.     n = -gb.max_n;        /* reflected */
  508.     colp = &virtrast[n * stride];
  509. if (colp != buildraster)
  510. panic("gffont drawchar colp != buildraster");
  511.     black = 0;
  512.  
  513.     /*
  514.      * Now interpret the character.
  515.      * `for (;;)' pushes everything off the right edge, alas.
  516.      */
  517. more:
  518.     c = pgetbyte(p);
  519.     if (GF_IsPaint(c))    /* faster? */
  520.         goto paint;
  521.     switch (GF_OpLen(c)) {
  522.  
  523.     case GPL_NONE:
  524.         break;
  525.  
  526.     case GPL_UNS1:
  527.         i = pgetbyte(p);
  528.         break;
  529.  
  530.     case GPL_UNS2:
  531.         pGetWord(p, i);
  532.         break;
  533.  
  534.     case GPL_UNS3:
  535.         pGet3Byte(p, i);
  536.         break;
  537.  
  538.     case GPL_SGN4:
  539.         pGetLong(p, i);
  540.         break;
  541.  
  542.     default:
  543.         panic("gffont drawchar GF_OpLen(%d) = %d", c, GF_OpLen(c));
  544.         /* NOTREACHED */
  545.     }
  546.  
  547.     switch (GF_TYPE(c)) {
  548.  
  549.     case GT_PAINT0:
  550. paint:
  551.         i = c - GF_PAINT_0;
  552.         /* FALLTHROUGH */
  553.  
  554.     case GT_PAINT:
  555.         /*
  556.          * Paint `i' bits in the current row at columns [m..m+i).
  557.          */
  558.         if (i && black) {
  559.             /* remember to adjust n bounds later */
  560.             wrotethisrow = 1;
  561.             /* adjust minimum m bound */
  562.             if (m < ob.min_m)
  563.                 ob.min_m = m;
  564.  
  565.             /*
  566.              * Finish the partial byte at colp.  There are 8-k
  567.              * bits to set to finish it, where k is the bit
  568.              * index value from m.  If we need to set fewer
  569.              * than 8-k bits, set them now and skip the rest
  570.              * of this.
  571.              */
  572.             c = 8 - btobi(m);
  573.             if (i < c) {    /* cannot finish it off */
  574.                 *colp |= UnSign8(lbits[i]) >> btobi(m);
  575.                 m += i;
  576.             } else {    /* finish it off */
  577.                 *colp++ |= rbits[btobi(m)];
  578.                 i -= c;
  579.                 m += c;
  580.  
  581.                 /*
  582.                  * Update m to reflect having written the
  583.                  * remaining i bits, then write them.
  584.                  * First write all the full bytes, then
  585.                  * start a partial byte with whatever
  586.                  * is left over, if anything.
  587.                  */
  588.                 m += i;
  589.                 i >>= 3;
  590.                 while (--i >= 0)
  591.                     *colp++ = 0xff;
  592.                 *colp |= lbits[btobi(m)];
  593.             }
  594.  
  595.             /* adjust maximum m bound */
  596.             if (m > ob.max_m)
  597.                 ob.max_m = m;
  598.         } else {
  599.             /*
  600.              * Add the bit index so that we round up whenever
  601.              * this fills the partial byte at colp.
  602.              */
  603.             colp += (i + btobi(m)) >> 3;
  604.             m += i;
  605.         }
  606.         black = !black;
  607.         break;
  608.  
  609.     case GT_EOC:        /* all done */
  610.         FIX_N_BOUNDS();
  611.         goto done;
  612.  
  613.     case GT_SKIP0:        /* skip no rows */
  614.         i = 0;
  615.         /* FALLTHROUGH */
  616.  
  617.     case GT_SKIP:        /* skip some rows, draw white */
  618.         m = 0;
  619.         black = 0;
  620.         goto skip_or_new_row;
  621.  
  622.     case GT_NEW_ROW:    /* next row near left col, draw black */
  623.         m = c - GF_NEW_ROW_0;
  624.         black = 1;
  625.         i = 0;            /* n offset is 1: skip no rows */
  626. skip_or_new_row:
  627.         FIX_N_BOUNDS();
  628.         n += i + 1;        /* += because reflected */
  629.         colp = &virtrast[n * stride + btoby(m)];
  630.         break;
  631.  
  632.     case GT_XXX:        /* special */
  633.         p += i;
  634.         break;
  635.  
  636.     case GT_YYY:        /* numspecial */
  637.         break;
  638.  
  639.     case GT_NOP:        /* dull */
  640.         break;
  641.  
  642.     case GT_BOC:        /* should not appear */
  643.     case GT_BOC1:
  644.     case GT_CHAR_LOC:
  645.     case GT_CHAR_LOC0:
  646.     case GT_PRE:
  647.     case GT_POST:
  648.     case GT_POSTPOST:
  649.     case GT_UNDEF:
  650.         error(0, 0, "unexpected GF opcode %d", c);
  651.         error(1, 0, "bad GF file \"%s\"", gfname);
  652.         /* NOTREACHED */
  653.  
  654.     default:
  655.         panic("gffont drawchar GF_TYPE(%d) = %d", c, GF_TYPE(c));
  656.         /* NOTREACHED */
  657.     }
  658.     goto more;
  659.  
  660. done:
  661.     /*
  662.      * The observed bounds `m' values are both off by gb.min_m, so
  663.      * fix them now.  CONSIDER ADJUSTING n HERE TOO
  664.      */
  665.     ob.min_m += gb.min_m;
  666.     ob.max_m += gb.min_m;
  667.  
  668.     /*
  669.      * If we used too much memory for the raster, copy it now.
  670.      */
  671.     if (mustcopy || tempb.min_n != ob.min_n || tempb.max_n != ob.max_n ||
  672.         btonb(ob.max_m - ob.min_m + 1) != stride)
  673.         return (copyit());
  674.  
  675.     /*
  676.      * If the left column bounds match, just move the raster in place.
  677.      */
  678.     if (tempb.min_m == ob.min_m) {
  679.         p = buildraster;
  680.         buildraster = NULL;
  681.         buildsize = 0;
  682.         return (p);
  683.     }
  684.  
  685.     /*
  686.      * The raster must be copied, but only because it is not
  687.      * `left justified'.
  688.      *
  689.      * CONSIDER DEFERRING THIS PHASE UNTIL THE RASTER IS USED
  690.      */
  691.     return (copyit());
  692. }
  693.  
  694. /*
  695.  * Copy the built raster to newly allocated space.
  696.  * We may need to shift all the bits left as well.
  697.  */
  698. char *
  699. copyit()
  700. {
  701.     register char *o, *p;
  702.     register int i, oldoff, newoff;
  703.     char *n;
  704.  
  705.     /*
  706.      * Compute the observed minimum stride.  If it is zero or negative,
  707.      * there is no raster at all, else allocate just enough space
  708.      * to hold the new raster.
  709.      */
  710.     newoff = btonb(ob.max_m - ob.min_m + 1);
  711.     if (newoff <= 0)
  712.         return (nullraster);
  713. if (ob.max_n < ob.min_n)
  714. panic("gffont copyit max_n < min_n");
  715.     n = malloc((unsigned) (newoff * (ob.max_n - ob.min_n + 1)));
  716.     if ((p = n) == NULL)
  717.         return (NULL);
  718.  
  719.     /*
  720.      * Compute the old stride.
  721.      */
  722.     oldoff = btonb(tempb.max_m - tempb.min_m + 1);
  723. if (oldoff < newoff)
  724. panic("gffont copyit oldoff < newoff");
  725.  
  726.     /*
  727.      * Point at the old raster, then add the offset to the first
  728.      * written row, and then the offset to the first written column.
  729.      */
  730.     o = buildraster;
  731.     o += (ob.max_n - tempb.max_n) * oldoff;
  732.     i = ob.min_m - tempb.min_m;
  733.     o += btoby(i);
  734.  
  735.     /*
  736.      * Now copy each row, doing shifting if required.
  737.      */
  738.     if ((i = btobi(i)) != 0) {    /* must shift, alas */
  739.         register int r = 8 - i, j, k;
  740.  
  741.         oldoff -= newoff;
  742.         for (k = ob.max_n; k >= ob.min_n; k--) {
  743.             for (j = newoff; --j >= 0;) {
  744.                 *p++ = *o++ << i;
  745.                 p[-1] |= UnSign8(*o) >> r;
  746.             }
  747.             o += oldoff;
  748.         }
  749.     } else if (oldoff > newoff) {    /* compressing columns */
  750.         for (i = ob.max_n; i >= ob.min_n; i--) {
  751.             bcopy(o, p, newoff);
  752.             o += oldoff;
  753.             p += newoff;
  754.         }
  755.     } else                /* just squeezing out extra rows */
  756.         bcopy(o, p, newoff * (ob.max_n - ob.min_n + 1));
  757.  
  758.     /* finally, return the copy */
  759.     return (n);
  760. }
  761.  
  762. /*
  763.  * Obtain the specified range of glyphs.
  764.  */
  765. static int
  766. gf_getgly(f, l, h)
  767.     register struct font *f;
  768.     int l, h;
  769. {
  770.     register struct glyph *g;
  771.     register struct char_loc *cl;
  772.     register char *p;
  773.     register i32 c;
  774.     register int i;
  775.     register i32 thisboc;
  776.     int abbrev;
  777.     struct gf_details *gd = ftogd(f);
  778.  
  779.     /*
  780.      * For each glyph, make sure there exists an instance of that
  781.      * character residue.  Go find the actual glyph (which may be
  782.      * arbitrarily far down a chain of pointers) and get its info.
  783.      */
  784.     for (cl = &gd->gd_cl[i = l]; i < h; i++, cl++) {
  785.         g = f->f_gly[i];
  786.         thisboc = cl->cl_p;
  787.  
  788.         /*
  789.          * Screw around locating the character for real.
  790.          */
  791.         while (thisboc != -1) {
  792.             p = gd->gd_base + thisboc;
  793. skip:
  794.             c = pgetbyte(p);
  795.             switch (GF_TYPE(c)) {
  796.  
  797.             case GT_XXX:
  798.                 switch (GF_OpLen(c)) {
  799.  
  800.                 case GPL_UNS1:
  801.                     c = pgetbyte(p);
  802.                     break;
  803.  
  804.                 case GPL_UNS2:
  805.                     pGetWord(p, c);
  806.                     break;
  807.  
  808.                 case GPL_UNS3:
  809.                     pGet3Byte(p, c);
  810.                     break;
  811.  
  812.                 case GPL_SGN4:
  813.                     pGetLong(p, c);
  814.                     break;
  815.  
  816.                 default:
  817.                     panic("gf_getgly GF_OpLen(%d) = %d",
  818.                         c, GF_OpLen(c));
  819.                     /* NOTREACHED */
  820.                 }
  821.                 p += c;
  822.                 goto skip;
  823.  
  824.             case GT_YYY:
  825.                 p += 4;
  826.                 goto skip;
  827.  
  828.             case GT_BOC:
  829.                 abbrev = 0;
  830.                 pGetLong(p, c);
  831.                 break;
  832.  
  833.             case GT_BOC1:
  834.                 abbrev = 1;
  835.                 c = pgetbyte(p);
  836.                 break;
  837.  
  838.             default:
  839.                 error(0, 0, "GF code %d; I expected BOC", c);
  840.                 error(1, 0, "bad GF file \"%s\"", f->f_path);
  841.                 /* NOTREACHED */
  842.             }
  843.             /*
  844.              * Found a BOC.  If it is the right character,
  845.              * go handle it.
  846.              */
  847.             if (c == i)
  848.                 goto handleit;
  849.             if ((c & 255) != i) {
  850.                 error(0, 0, "%d != %d mod 256", c, i);
  851.                 error(1, 0, "Bad GF file \"%s\"", f->f_path);
  852.             }
  853.             /*
  854.              * Follow the backpointer.
  855.              */
  856.             if (abbrev)
  857.                 thisboc = -1;
  858.             else
  859.                 pGetLong(p, thisboc);
  860.         }
  861.  
  862.         /*
  863.          * If we get here, the glyph is not valid after all.
  864.          */
  865.         continue;
  866.     
  867.         /*
  868.          * The glyph is okay.  Set it up.
  869.          */
  870. handleit:
  871.         g->g_flags = GF_VALID;
  872. #ifdef notyet
  873.         g->g_xescapement = cl->cl_dx;
  874.         g->g_yescapement = cl->cl_dy;
  875. #endif
  876.         g->g_tfmwidth = cl->cl_w;
  877.         if (!abbrev)
  878.             p += 4;        /* skip backpointer */
  879.         if ((p = drawchar(p, abbrev, gd->gd_gb, f->f_path)) == NULL)
  880.             return (-1);    /* ??? */
  881.         if (p == nullraster)
  882.             p = NULL;
  883.         /* set height &c based on observed bounds */
  884.         g->g_height = ob.max_n - ob.min_n + 1;
  885.         g->g_width = ob.max_m - ob.min_m + 1;
  886.         g->g_yorigin = ob.max_n;
  887.         g->g_xorigin = -ob.min_m;
  888.         g->g_raster = p;
  889.         g->g_rotation = ROT_NORM;
  890.     }
  891.     return (0);
  892. }
  893.  
  894. /*
  895.  * Obtain rasters for the specified glyphs.  We did this above, while
  896.  * adjusting the bounding boxes, so this routine should never get called.
  897.  */
  898. static int
  899. gf_rasterise(f, l, h)
  900.     struct font *f;
  901.     int l, h;
  902. {
  903.  
  904.     panic("gf_rasterise(%s, %d, %d)", f->f_path, l, h);
  905. }
  906.  
  907. /*
  908.  * Discard the font details.
  909.  */
  910. static
  911. gf_freefont(f)
  912.     struct font *f;
  913. {
  914.     struct gf_details *gd;
  915.  
  916.     if ((gd = ftogd(f)) != NULL) {
  917.         free(gd->gd_body);
  918.         free((char *) gd);
  919.     }
  920. }
  921.